﻿namespace Vdc.Grid
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;
    using System.Text.RegularExpressions;

    internal class JavaScriptObjectDeserializer
    {
        private int _depthLimit;
        internal JavaScriptString _s;
        private JavaScriptSerializer _serializer;
        private const string DateTimePrefix = "\"\\/Date(";
        private const int DateTimePrefixLength = 8;

        private JavaScriptObjectDeserializer(string input, int depthLimit, JavaScriptSerializer serializer)
        {
            this._s = new JavaScriptString(input);
            this._depthLimit = depthLimit;
            this._serializer = serializer;
        }

        private void AppendCharToBuilder(char? c, StringBuilder sb)
        {
            if (((c == '"') || (c == '\'')) || (c == '/'))
            {
                sb.Append(c);
            }
            else if (c == 'b')
            {
                sb.Append('\b');
            }
            else if (c == 'f')
            {
                sb.Append('\f');
            }
            else if (c == 'n')
            {
                sb.Append('\n');
            }
            else if (c == 'r')
            {
                sb.Append('\r');
            }
            else if (c == 't')
            {
                sb.Append('\t');
            }
            else
            {
                if (c != 'u')
                {
                    throw new ArgumentException(this._s.GetDebugString("JSON_BadEscape"));
                }
                sb.Append((char) int.Parse(this._s.MoveNext(4), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
            }
        }

        internal static object BasicDeserialize(string input, int depthLimit, JavaScriptSerializer serializer)
        {
            JavaScriptObjectDeserializer deserializer = new JavaScriptObjectDeserializer(input, depthLimit, serializer);
            object obj2 = deserializer.DeserializeInternal(0);
            char? nextNonEmptyChar = deserializer._s.GetNextNonEmptyChar();
            int? nullable2 = nextNonEmptyChar.HasValue ? new int?(nextNonEmptyChar.GetValueOrDefault()) : null;
            if (nullable2.HasValue)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "JSON_IllegalPrimitive", new object[0]));
            }
            return obj2;
        }

        private char CheckQuoteChar(char? c)
        {
            if (c == '\'')
            {
                return c.Value;
            }
            if (c != '"')
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_StringNotQuoted"));
            }
            return '"';
        }

        private IDictionary<string, object> DeserializeDictionary(int depth)
        {
            IDictionary<string, object> dictionary = null;
            char? nextNonEmptyChar;
            char? nullable2;
            char? nullable3;
            if (this._s.MoveNext() != '{')
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_ExpectedOpenBrace"));
            }
        Label_003F:
            nullable2 = nextNonEmptyChar = this._s.GetNextNonEmptyChar();
            int? nullable4 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
            if (nullable4.HasValue)
            {
                this._s.MovePrev();
                if (nextNonEmptyChar == ':')
                {
                    throw new ArgumentException(this._s.GetDebugString("JSON_InvalidMemberName"));
                }
                string str = null;
                if (nextNonEmptyChar != '}')
                {
                    str = this.DeserializeMemberName();
                    if (string.IsNullOrEmpty(str))
                    {
                        throw new ArgumentException(this._s.GetDebugString("JSON_InvalidMemberName"));
                    }
                    if (this._s.GetNextNonEmptyChar() != ':')
                    {
                        throw new ArgumentException(this._s.GetDebugString("JSON_InvalidObject"));
                    }
                }
                if (dictionary == null)
                {
                    dictionary = new Dictionary<string, object>();
                    if (string.IsNullOrEmpty(str))
                    {
                        nextNonEmptyChar = this._s.GetNextNonEmptyChar();
                        goto Label_01CD;
                    }
                }
                object obj2 = this.DeserializeInternal(depth);
                dictionary[str] = obj2;
                nextNonEmptyChar = this._s.GetNextNonEmptyChar();
                if (nextNonEmptyChar != '}')
                {
                    if (nextNonEmptyChar != ',')
                    {
                        throw new ArgumentException(this._s.GetDebugString("JSON_InvalidObject"));
                    }
                    goto Label_003F;
                }
            }
        Label_01CD:
            nullable3 = nextNonEmptyChar;
            if ((nullable3.GetValueOrDefault() != '}') || !nullable3.HasValue)
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_InvalidObject"));
            }
            return dictionary;
        }

        private object DeserializeInternal(int depth)
        {
            if (++depth > this._depthLimit)
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_DepthLimitExceeded"));
            }
            char? nextNonEmptyChar = this._s.GetNextNonEmptyChar();
            char? nullable2 = nextNonEmptyChar;
            int? nullable3 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
            if (!nullable3.HasValue)
            {
                return null;
            }
            this._s.MovePrev();
            if (this.IsNextElementDateTime())
            {
                return this.DeserializeStringIntoDateTime();
            }
            if (IsNextElementObject(nextNonEmptyChar))
            {
                IDictionary<string, object> o = this.DeserializeDictionary(depth);
                if (o.ContainsKey("__type"))
                {
                    return ObjectConverter.ConvertObjectToType(o, null, this._serializer);
                }
                return o;
            }
            if (IsNextElementArray(nextNonEmptyChar))
            {
                return this.DeserializeList(depth);
            }
            if (IsNextElementString(nextNonEmptyChar))
            {
                return this.DeserializeString();
            }
            return this.DeserializePrimitiveObject();
        }

        private IList DeserializeList(int depth)
        {
            char? nextNonEmptyChar;
            char? nullable8;
            IList list = new ArrayList();
            if (this._s.MoveNext() != '[')
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_InvalidArrayStart"));
            }
            bool flag = false;
            do
            {
                char? nullable2 = nextNonEmptyChar = this._s.GetNextNonEmptyChar();
                int? nullable3 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
                if (!nullable3.HasValue || (nextNonEmptyChar == ']'))
                {
                    goto Label_0122;
                }
                this._s.MovePrev();
                object obj2 = this.DeserializeInternal(depth);
                list.Add(obj2);
                flag = false;
                nextNonEmptyChar = this._s.GetNextNonEmptyChar();
                if (nextNonEmptyChar == ']')
                {
                    goto Label_0122;
                }
                flag = true;
                nullable8 = nextNonEmptyChar;
            }
            while ((nullable8.GetValueOrDefault() == ',') && nullable8.HasValue);
            throw new ArgumentException(this._s.GetDebugString("JSON_InvalidArrayExpectComma"));
        Label_0122:
            if (flag)
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_InvalidArrayExtraComma"));
            }
            if (nextNonEmptyChar != ']')
            {
                throw new ArgumentException(this._s.GetDebugString("JSON_InvalidArrayEnd"));
            }
            return list;
        }

        private string DeserializeMemberName()
        {
            char? nextNonEmptyChar = this._s.GetNextNonEmptyChar();
            char? nullable2 = nextNonEmptyChar;
            int? nullable3 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
            if (!nullable3.HasValue)
            {
                return null;
            }
            this._s.MovePrev();
            if (IsNextElementString(nextNonEmptyChar))
            {
                return this.DeserializeString();
            }
            return this.DeserializePrimitiveToken();
        }

        private object DeserializePrimitiveObject()
        {
            double num;
            string s = this.DeserializePrimitiveToken();
            if (s.Equals("null"))
            {
                return null;
            }
            if (s.Equals("true"))
            {
                return true;
            }
            if (s.Equals("false"))
            {
                return false;
            }
            bool flag = s.IndexOf('.') >= 0;
            if (s.LastIndexOf("e", StringComparison.OrdinalIgnoreCase) < 0)
            {
                decimal num2;
                if (!flag)
                {
                    int num3;
                    long num4;
                    if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out num3))
                    {
                        return num3;
                    }
                    if (long.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out num4))
                    {
                        return num4;
                    }
                }
                if (decimal.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out num2))
                {
                    return num2;
                }
            }
            if (!double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out num))
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "JSON_IllegalPrimitive", new object[0]));
            }
            return num;
        }

        private string DeserializePrimitiveToken()
        {
            StringBuilder builder = new StringBuilder();
            char? nullable2 = null;
            while (true)
            {
                char? nullable = nullable2 = this._s.MoveNext();
                int? nullable3 = nullable.HasValue ? new int?(nullable.GetValueOrDefault()) : null;
                if (!nullable3.HasValue)
                {
                    goto Label_009E;
                }
                if ((!char.IsLetterOrDigit(nullable2.Value) && (nullable2.Value != '.')) && (((nullable2.Value != '-') && (nullable2.Value != '_')) && (nullable2.Value != '+')))
                {
                    break;
                }
                builder.Append(nullable2);
            }
            this._s.MovePrev();
        Label_009E:
            return builder.ToString();
        }

        private string DeserializeString()
        {
            StringBuilder sb = new StringBuilder();
            bool flag = false;
            char? c = this._s.MoveNext();
            char ch = this.CheckQuoteChar(c);
            while (true)
            {
                char? nullable2 = c = this._s.MoveNext();
                int? nullable3 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
                if (!nullable3.HasValue)
                {
                    throw new ArgumentException(this._s.GetDebugString("JSON_UnterminatedString"));
                }
                if (c == '\\')
                {
                    if (flag)
                    {
                        sb.Append('\\');
                        flag = false;
                    }
                    else
                    {
                        flag = true;
                    }
                }
                else if (flag)
                {
                    this.AppendCharToBuilder(c, sb);
                    flag = false;
                }
                else
                {
                    char? nullable4 = c;
                    int num = ch;
                    if ((nullable4.GetValueOrDefault() == num) && nullable4.HasValue)
                    {
                        return sb.ToString();
                    }
                    sb.Append(c);
                }
            }
        }

        private object DeserializeStringIntoDateTime()
        {
            long num;
            Match match = Regex.Match(this._s.ToString(), "^\"\\\\/Date\\((?<ticks>-?[0-9]+)(?:[a-zA-Z]|(?:\\+|-)[0-9]{4})?\\)\\\\/\"");
            if (long.TryParse(match.Groups["ticks"].Value, out num))
            {
                this._s.MoveNext(match.Length);
                return new DateTime((num * 0x2710L) + JavaScriptSerializer.DatetimeMinTimeTicks, DateTimeKind.Utc);
            }
            return this.DeserializeString();
        }

        private static bool IsNextElementArray(char? c)
        {
            return (c == '[');
        }

        private bool IsNextElementDateTime()
        {
            string a = this._s.MoveNext(8);
            if (a != null)
            {
                this._s.MovePrev(8);
                return string.Equals(a, "\"\\/Date(", StringComparison.Ordinal);
            }
            return false;
        }

        private static bool IsNextElementObject(char? c)
        {
            return (c == '{');
        }

        private static bool IsNextElementString(char? c)
        {
            return ((c == '"') || (c == '\''));
        }
    }
}

